/*生产者和消费者之间的同步和互斥是通过信号量实现的：

lock信号量用于保护对缓冲区的访问，只允许一个线程访问缓冲区。
sem_p信号量表示生产者线程可以生产的空槽数量。初始值为缓冲区大小，每次生产一个数据项，该值减少。
sem_c信号量表示消费者线程可以消费的数据项数量。初始值为0，表示缓冲区初始为空，消费者需要等待生产者产生数据。
当生产者线程生产一个数据项时，它会先等待sem_p信号量，确保有空槽可供使用。然后，它获取lock信号量，访问缓冲区，将数据项放入其中，更新写索引，并释放lock信号量。最后，它发送一个sem_c信号量，告知消费者有一个数据项可供消费。

当消费者线程消费一个数据项时，它会先等待sem_c信号量，确保有数据项可供消费。然后，它获取lock信号量，访问缓冲区，从中读取数据项，更新读索引，并释放lock信号量。最后，它发送一个sem_p信号量，告知生产者有一个空槽可供生产。

通过这种方式，生产者和消费者线程可以按照互斥和同步的方式访问和操作共享的缓冲区，实现了线程之间的协作和数据交换。*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>

#define SIZE 5

int buf[SIZE];                  // 缓冲区
int write_index = 0;            // 写索引
int read_index = 0;             // 读索引
int idx = 0;                    // 生产的数据项
sem_t lock;                     // 互斥信号量，用于保护对缓冲区的访问
sem_t sem_c, sem_p;             // 信号量，用于生产者和消费者之间的同步

void *produce(void *arg){
    while(1){
        sem_wait(&sem_p);        // 等待生产信号量
        sem_wait(&lock);         // 互斥访问缓冲区
        
        printf("Produce: %d\n",idx);
        buf[write_index] = idx; // 将数据项放入缓冲区
        idx++;
        
        write_index = (write_index+1)%SIZE; // 更新写索引，循环队列        

        sem_post(&lock);         // 释放互斥信号量
        sem_post(&sem_c);        // 发送消费信号量        
        sleep(2);
    }    
   
    return 0;
}

void *consume(void *arg){
    int data;

    while(1){
        sem_wait(&sem_c);        // 等待消费信号量
        sem_wait(&lock);         // 互斥访问缓冲区
        
        data = buf[read_index];  // 从缓冲区中读取数据项
        buf[read_index] = -1;    // 清空读取的位置
        read_index = (read_index+1)%SIZE; // 更新读索引，循环队列
        printf("Consume: %d\n",data);

        sem_post(&lock);         // 释放互斥信号量
        sem_post(&sem_p);        // 发送生产信号量        
        sleep(1);
    }    
   
    return 0;
}

int main(){
    pthread_t con, pros;

    sem_init(&lock, 0, 1);      // 初始化互斥信号量
    sem_init(&sem_p, 0, SIZE);  // 初始化生产信号量，初始值为缓冲区大小，表示缓冲区有多少空槽可供生产者使用
    sem_init(&sem_c, 0, 0);     // 初始化消费信号量，初始值为0，表示缓冲区初始为空，消费者需要等待生产者产生数据

    pthread_create(&pros, NULL, produce, NULL);   // 创建生产者线程
    pthread_create(&con, NULL, consume, NULL);    // 创建消费者线程

    pthread_join(con, 0);    // 等待消费者线程结束
    pthread_join(pros, 0);   // 等待生产者线程结束

    sem_destroy(&lock);      // 销毁互斥信号量
    sem_destroy(&sem_p);     // 销毁生产信号量
    sem_destroy(&sem_c);     // 销毁消费信号量

    return 0;
}
